package components.brush
{
	import UIUtils.uif_color;
	import UIUtils.uif_util;
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.BlendMode;
	import flash.display.GradientType;
	import flash.display.IBitmapDrawable;
	import flash.display.Shape;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.filters.BlurFilter;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	public class c_baseBrush extends EventDispatcher {
		protected var _stamp				: IBitmapDrawable;
		protected var _tmpLayer				: BitmapData;
		protected var _copyLayer			: BitmapData;
		protected var _brushLayer			: Bitmap;
		protected var _brushData			: BitmapData;
		protected var _prevPoint			: Point;
		protected var _blurFilter			: BlurFilter;
		
		public var stepLen				: Number;
		public var blendMode			: String;
		public var colorTransform		: ColorTransform;
		
		public function c_baseBrush() {
			super();
			stepLen 	= 6;
			_stamp 		= createSpotStamp(10, 1);
			blendMode 	= BlendMode.NORMAL;
			_blurFilter = new BlurFilter(0, 0, 3);
		}
		
		public function get stamp(): IBitmapDrawable {
			return _stamp;
		}
		
		public function set stamp(a_stamp: IBitmapDrawable): void {
			setStamp(a_stamp);
		}
		
		public function get blur(): Number {
			return _blurFilter.blurX;
		}
		
		public function set blur(a_blur: Number): void {
			_blurFilter.blurX = a_blur;
			_blurFilter.blurY = a_blur;
		}
		
		public function get color(): uint {
			return colorTransform?uif_color.RGB(
				colorTransform.redMultiplier * 0xFF,
				colorTransform.greenMultiplier * 0xFF,
				colorTransform.blueMultiplier * 0xFF
			):0;
		}
		
		public function set color(a_color: uint): void {
			if (!colorTransform) colorTransform = new ColorTransform();
			var a: Array = uif_color.uintToRGBA(a_color);
			colorTransform.redMultiplier 	= a[1] / 0xFF;
			colorTransform.greenMultiplier 	= a[2] / 0xFF;
			colorTransform.blueMultiplier 	= a[3] / 0xFF;
		}
		
		protected function setStamp(a_stamp: IBitmapDrawable): void {
			_stamp = a_stamp;
		}
		
		public function drawLine(drawLayer	: BitmapData, startPoint: Point, endPoint: Point, 
								 stampScale	: Point=null, stepLen: Number=1): void {
			var direct	: Point 	= endPoint.subtract(startPoint);
			var len		: Number 	= direct.length;
			var steps	: int 		= Math.ceil(len / stepLen);
			var p		: Point 	= startPoint.clone();
			direct.normalize(stepLen);
			for (var i: int; i<steps; i++) {
				drawStamp(drawLayer, p, stampScale);
				p = p.add(direct);
			}
		}
		
		public function drawStamp(drawLayer		: BitmapData, point: Point, stampScale	: Point=null): void {
			var mat		: Matrix	= new Matrix();
			if (stampScale) mat.scale(stampScale.x, stampScale.y);
			mat.translate(point.x, point.y);
			drawStampA(drawLayer, mat);
		}
		
		protected function drawStampA(drawLayer		: BitmapData, mat: Matrix): void {
			drawLayer.draw(stamp, mat, null, null, null, true);
		}
		
		public static function createSpotStamp(radius: Number, soft: Number=0): IBitmapDrawable {
			var shape: Shape = new Shape();
			if (soft == 0) shape.graphics.beginFill(0xFFFFFF, 1);
			else {
				var mat: Matrix = new Matrix();
				mat.createGradientBox(radius * 2, radius * 2, 0, -radius, -radius);
				shape.graphics.beginGradientFill(GradientType.RADIAL, [0xFFFFFF, 0xFFFFFF, 0xFFFFFF], 
				[1, 0.4, 0], [Math.round((1 - soft) * 0xFF), 0x7F, 0xFF], mat);
			}
			shape.graphics.drawCircle(0, 0, radius);
			return shape;			
		}
		
		public function beginSession(drawLayer		: BitmapData, point: Point): void {
			_brushData	= new BitmapData(drawLayer.width, drawLayer.height, true, 0);
			_brushLayer = new Bitmap();
			_brushLayer.blendMode = BlendMode.LAYER;
			_copyLayer	= drawLayer.clone();
			_tmpLayer 	= drawLayer;
			_prevPoint 	= point;
			drawStamp(_brushData, point, null);
			copyToLayerSessionStep();
		}
		
		public function sessionPaintTo(point: Point): void {
			drawLine(_brushData, _prevPoint, point, null, stepLen);
			copyToLayerSessionStep();
			_prevPoint = point;
		}
		
		protected function copyToLayerSessionStep(): void {
			if (blur > 0) {
				_brushLayer.bitmapData = new BitmapData(_brushData.width, _brushData.height, true, 0);
				_brushLayer.bitmapData.applyFilter(_brushData, _brushData.rect, uif_util.NULLPOINT, _blurFilter);
			} else _brushLayer.bitmapData = _brushData;
			
			_tmpLayer.fillRect(_tmpLayer.rect, 0);
			_tmpLayer.draw(_copyLayer);
			_tmpLayer.draw(_brushLayer, null, colorTransform, blendMode);
			if (_brushLayer.bitmapData != _brushData) _brushLayer.bitmapData.dispose();
		}
		
		public function cancelSession(): void {
			_tmpLayer.fillRect(_tmpLayer.rect, 0);
			_tmpLayer.draw(_copyLayer);
			_copyLayer.dispose();
		}
		
		public function endSession(): void {
			_copyLayer.dispose();
		}
		
		public function get bounds(): Rectangle {
			return new Rectangle();
		}
		
		public function createStampImage(): BitmapData {
			return null;
		}
	}
}